using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.OpenGLAttributes;

namespace SharpGL.SceneGraph.Effects
{
    /// <summary>
    /// The OpenGLAttributes are an effect that can set 
    /// any OpenGL attributes.
    /// </summary>
    [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(/*IsReference = true, */Name = "OpenGLAttributesEffect", Namespace = "SharpGL.SceneGraph")]
    public class OpenGLAttributesEffect : Effect
    {
        #region Private Consts

        private static readonly string defaultName = "OpenGL attributes effect";

        #endregion Private Consts

        #region Private Fields

        /// <summary>
        /// The OpenGL attributes group.
        /// </summary>
        [DataMember()]
        private OpenGLAttributesGroup attributesGroup = new OpenGLAttributesGroup();

        #endregion Private Fields

        #region Private Methods

        private void OnOpenGLAttributesGroupPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyPropertyChanged("AttributesGroup"/*sender.GetType()*/ + "." + e.PropertyName);
        }

        #endregion Private Methods

        #region Protected Methods

        protected override void OnDeserialized()
        {
            attributesGroup.PropertyChanged += new PropertyChangedEventHandler(OnOpenGLAttributesGroupPropertyChanged);
        }

        #endregion Protected Methods

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="OpenGLAttributesEffect"/> class.
        /// </summary>
        public OpenGLAttributesEffect()
        {
            Name = defaultName;
            attributesGroup.PropertyChanged += new PropertyChangedEventHandler(OnOpenGLAttributesGroupPropertyChanged);
        }

        #endregion Constructors

        #region Public Methods

        /// <summary>
        /// Pushes the effect onto the specified parent element.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="parentElement">The parent element.</param>
        public override void Push(OpenGL gl, SceneElement parentElement)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Push the attribute stack.
                gl.PushAttrib(attributesGroup.AttributeFlags);
                attributesGroup.SetAttributes(gl);

                if (parentElement is IOwnOpenGLAttributesApply)
                    ((IOwnOpenGLAttributesApply)parentElement).ApplyAttributes(gl, AttributesGroup);
            }
        }

        /// <summary>
        /// Pops the effect off the specified parent element.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="parentElement">The parent element.</param>
        public override void Pop(OpenGL gl, SceneElement parentElement)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Pop the attribute stack.
                gl.PopAttrib();
            }
        }

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the linear transformation.
        /// </summary>
        /// <value>
        /// The linear transformation.
        /// </value>
        [Description("The OpenGL attributes group."), Category("Effect")]
        public OpenGLAttributesGroup AttributesGroup
        {
            get { return attributesGroup; }
            set
            {
                if (attributesGroup != value)
                {
                    if (value == null)
                        attributesGroup.ResetAllAttributes();
                    else
                    {
                        attributesGroup.PropertyChanged -= new PropertyChangedEventHandler(OnOpenGLAttributesGroupPropertyChanged);
                        attributesGroup = value;
                        attributesGroup.PropertyChanged += new PropertyChangedEventHandler(OnOpenGLAttributesGroupPropertyChanged);
                    }

                    NotifyPropertyChanged("AttributesGroup");
                }
            }
        }

        #endregion Public Properties
    }
}
